# This file is part of the AutoMAT distribution (https://bitbucket.com/mahomaho/AutoMAT).
# Copyright (c) 2019 Mattias Holmqvist.
# 
# AutoMAT is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# 
# AutoMAT is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with AutoMAT.  If not, see <https://www.gnu.org/licenses/>.

from collections import defaultdict, OrderedDict
from enum import Enum
import csv
import sys, os

from AutoMAT import *
from AutoMAT import _vprint as vprint
from helpers.rtehelper import *
import helpers.rtehelper

_outdir=''
_matlabTypeWorkaround=False

sys.path.append(os.path.abspath('.'))

# and finally get the conf
EcucValueCollection = autosar_r4p0.EcucValueCollection.instances()[0]
extract = EcucValueCollection.ecuExtract.ref()
rte = EcucValueCollection.ecucValue.EcucModuleConfigurationValues.select.findfirst(lambda e:e.ref().definition.val().split('/')[-1] == 'Rte').ref()
com = EcucValueCollection.ecucValue.EcucModuleConfigurationValues.select.findfirst(lambda e:e.ref().definition.ref().refinedModuleDef.val().split('/')[-1] == 'Com', default=ModelNone).ref()
rootcomposition = extract.rootSoftwareComposition[0]

class CWriter():
	_indent = 0
	_filename = None
	_content=None
	_file=None
	def __init__(self, filename):
		self._filename = filename
		self._content=''
		vprint('opened file ' + filename + ' for write')
	
	def __lshift__(self, val):
		lines=(x.strip() for x in val.split('\n'))
		for line in lines:
			indent = self._indent
			self._indent+=line.count('{') - line.count('}') + line.count('(') - line.count(')')
			if line.startswith('case') or line.startswith('}'):
				indent-=1
			line='\t'*indent + line
			#print(line)
			self._content+=line + '\n'
		return self
	
	def close(self):
		global _outdir
		os.makedirs(_outdir, exist_ok=True)
		with open(_outdir+'/'+self._filename,'w') as f:
			f.write(self._content)
		vprint(f'file {self._filename} closed')

class _Rte_type_h():
	_handledtypes = None
	_rte_types_includes = None
	_typedefs = None
	_pimtypes = None
	def __init__(self):
		self._handledtypes = set()
		self._rte_types_includes = {}
		self._typedefs = OrderedDict()
		self._pimtypes = ''
	
		for impltype in autosar_r4p0.ImplementationDataType.instances():
			name=impltype.shortName.val()
			try:
				deps = RteList()
				props = impltype.swDataDefProps
				if impltype.typeEmitter.val() not in  ('RTE', 'BSW', None):
					self._rte_types_includes[impltype.typeEmitter.val()] = f'#include "{impltype.typeEmitter.val()}"'
					self._handledtypes.add(name)
					continue
				elif impltype.category.val() in ('VALUE','BOOLEAN'):
					if not props.baseType.ref().nativeDeclaration.val()==None:
						res = f'typedef {props.baseType.ref().nativeDeclaration.val()} {name};'
					else:
						#type should be emitted in this case
						self._handledtypes.add(name)
						continue
				elif impltype.category.val() == 'TYPE_REFERENCE':
					# redefinition type
					typename = props.implementationDataType.ref().shortName.val()
					res = f'typedef {typename} {name};'
					deps.append(typename)
				elif impltype.category.val() == 'ARRAY':
					impltypeelem = impltype.subElement[0]
					props = impltypeelem.swDataDefProps
					if impltypeelem.category.val() in ('VALUE','BOOLEAN'):
						typename = props.baseType.ref().nativeDeclaration.val()
					elif impltypeelem.category.val() == 'TYPE_REFERENCE':
						typename = props.implementationDataType.ref().shortName.val()
						deps.append(typename)
					else:
						raise 'not supported'
					res = f'''typedef {typename} {name}'''
					for dim in impltype.subElement:
						res += f'[{dim.arraySize.val()}]'
					res += ';'
				elif impltype.category.val() == 'DATA_REFERENCE':
					tqlA=default('',props).swPointerTargetProps.swDataDefProps.swImplPolicy.val().name
					tqlB=default("",props).swImplPolicy.val().name
					addtqlA=default("",props).swPointerTargetProps.swDataDefProps.additionalNativeTypeQualifier.val().name
					addtqlB=default("",props).additionalNativeTypeQualifier.val().name
					if props.swPointerTargetProps.targetCategory.val() in ('VALUE','BOOLEAN'):
						typename = props.swPointerTargetProps.swDataDefProps.baseType.ref().nativeDeclaration.val()
					elif props.swPointerTargetProps.targetCategory.val() == 'TYPE_REFERENCE':
						typename = props.swPointerTargetProps.swDataDefProps.implementationDataType.ref().shortName.val()
						deps.append(typename)
					else:
						raise 'not supported'
					res=f'typedef {tqlA} {addtqlA} {typename} * {tqlB} {addtqlB} {name};'
						
				else:
					raise 'not supported'
				#print(res)
			except:
				print(f'Failed to include implementationtype {name}')
				continue
			self._typedefs[name] = (res,deps)

	def AddPimType(self, pimtype):
		self._pimtypes += pimtype + '\n'
		
	def Write_Rte_type(self):
		c = CWriter('Rte_Type.h')
		c << '''#ifndef RTE_TYPE_H
#define RTE_TYPE_H

#include "Rte.h"'''
		for h in self._rte_types_includes:
			c << '#include "'+h+'"'
		c << ''
		numfailed=0
		while len(self._typedefs) > 0:
			try:
				name,(val,deps) = self._typedefs.popitem(last=False)
				for dep in deps:
					if dep==None:
						print(f'error: implementation dependency for {name} missing')
					elif dep not in self._handledtypes:
						numfailed+=1
						self._typedefs[name] = (val,deps)
						raise Exception('wait with type until deps generated')
				if _matlabTypeWorkaround:
					c << f'#define _DEFINED_TYPEDEF_FOR_{name}_'
				c << val
				self._handledtypes.add(name)
				numfailed=0
			except Exception as ignore:
				# this is expected, generate the type when all deps are generated
				if numfailed>=len(self._typedefs):
					#cannot generate the last types
					print('circular dependencies makes it impossible to generate all types')
					break
		c << self._pimtypes
		c << '''
#endif // RTE_TYPE_H
'''
		c.close()

class CSV():
	class Instance():
		class DataElement():
			_dataelementref=None
			_comSignalRef=None
			_type=None
			_compu=None
			#_initval=None
			_rxcomspec=RteList()
			_txcomspec=None
			_runnables=None
			_storeLocal=None
			_buf_name=None
			def __init__(self, dataelement,port,behavior,instance):
				self._dataelementref=RteList()
				self._comSignalRef=RteList()
				self._type=TYPE(dataelement.type.ref(),behavior)
				self._runnables=defaultdict(RteList)
				self._storeLocal=False
				self._buf_name=f'Rte_{instance.shortName.val()}_{port.shortName.val()}_{dataelement.shortName.val()}'
				if isinstance(port, autosar_r4p0.RPortPrototype):
					if not port.requiredComSpec==None:
						self._rxcomspec=dataelement.references().select.findfirst(lambda e:e.parent().parent() == port).parent()
				else:
					if not port.providedComSpec==None:
						self._txcomspec=dataelement.references().select.findfirst(lambda e:e.parent().parent() == port).parent()
			def needProtection(self):
				if self._storeLocal:
					if self._type.isAtomic():
						return False
				elif  default(1,min)((e._type.isAtomic() for e in self._dataelementref if e._storeLocal)) > 0:
					return False
				runnables=list(r for rlist in self._runnables.values() for r in rlist)
				minprio=min((runnable._minprio for runnable in runnables))
				# why is a different list used when calculating maxprio?
				morerunnables=list(r for dlist in self._dataelementref for rlist in dlist._runnables.values() for r in rlist) + runnables
				maxprio=max((runnable._minprio for runnable in morerunnables))
				return minprio < maxprio
			def print_read(self,to_varptr):
				res=""
				if self._type.isArray():
					to_var=to_varptr
				else:
					if to_varptr[0]=='&':
						to_var=to_varptr[1:]
					else:
						to_var='*'+to_varptr
				if self._dataelementref.__len__() > 0:
					if self._storeLocal:
						res+=f'extern {self._type.name()} {self._buf_name};\n'
						res+=self._type.copy(f'{to_var}',self._type, self._buf_name)
					else:
						res+=f'extern {self._dataelementref[0]._type.name()} {self._dataelementref[0]._buf_name};\n'
						res+=self._type.copy(f'{to_var}',self._dataelementref[0]._type, self._dataelementref[0]._buf_name)
				for (systemsig,isig,comSig) in self._comSignalRef:
					basetype=isig.networkRepresentationProps.baseType.ref()
					# todo: this is wrong, should take compu method from system signal instead
					compu=isig.networkRepresentationProps.compuMethod.ref()
					comType=TYPE(basetype)
					comType._compu=compu
					if comType.ScalingNeeded(self._type):
						res+=f'{{\n{basetype.nativeDeclaration.val()} temp;\n'
						res+=f'Com_ReceiveSignal(ComConf_{comSig.definition.val().split("/")[-1]}_{comSig.shortName.val()}, &temp);\n'
						res+=self._type.copy(f'{to_var}',comType,'temp') + '}\n'
					else:
						res+=f'Com_ReceiveSignal(ComConf_{comSig.definition.val().split("/")[-1]}_{comSig.shortName.val()}, {to_varptr});\n'
				return res
			def print_write(self, var):
				res=""
				if self._storeLocal:
					res+=f'extern {self._type.name()} {self._buf_name};\n'
					res+=self._type.copy(self._buf_name,self._type,var)
				for rxdataelement in (e for e in self._dataelementref if e._storeLocal):
					res+=f'extern {rxdataelement._type.name()} {rxdataelement._buf_name};\n'
					res+=rxdataelement._type.copy(rxdataelement._buf_name,self._type,var)
						
				for (systemsig,isig,comSig) in self._comSignalRef:
					basetype=isig.networkRepresentationProps.baseType.ref()
					# todo: this is wrong, should take compu method from system signal instead
					compu=isig.networkRepresentationProps.compuMethod.ref()
					comType=TYPE(basetype)
					comType._compu=compu
					if comType.ScalingNeeded(self._type):
						res+=f'{{\n{basetype.nativeDeclaration.val()} temp;\n'
						res+=comType.copy('temp',self._type,var)
						res+=f'Com_SendSignal(ComConf_{comSig.definition.val().split("/")[-1]}_{comSig.shortName.val()}, &temp);\n}}\n'
					else:
						res+=f'Com_SendSignal(ComConf_{comSig.definition.val().split("/")[-1]}_{comSig.shortName.val()}, &{var});\n'
				return res
		class CalParam():
			_runnables=None
			_type=None
			def __init__(self,param,behavior):
				self._runnables=RteList()
				self._type=TYPE(param.type.ref(),behavior)
		class CSServer():
			_dataelementref=None
			_operation=None
			_port=None
			_runnable=None
			_mapping=None
			_args=None
			def __init__(self,operation,port,runnable,mapping,intbeh):
				self._dataelementref=RteList()
				self._operation=operation
				self._port=port
				self._runnable=runnable
				runnable._csServer=self
				self._mapping=mapping
				self._args=RteList()
				portApiOption=intbeh.portAPIOption.select.findall(lambda e:e.port.ref() == port)
				for i,arg in enumerate(portApiOption.portArgValue):
					self._args.append(('IN',TYPE(arg.valueType.ref(),intbeh),f'arg_{i}'))
				for arg in operation.argument:
					self._args.append((arg.direction.val().value,TYPE(arg.type.ref(),intbeh),arg.shortName.val()))
			def print_def(self):
				if not self._operation.possibleError==None:
					ret='extern Std_ReturnType '
				else:
					ret='extern void '
				ret+=self._runnable._runnable.symbol.val()+'('
				if self._args==None:
					ret+='void'
				else:
					args=[]
					for direction,typeref,varname, in self._args:
						if direction=='IN':
							if typeref.isArray():
								args.append(f'\n/* IN */ const {typeref.impl_name()} {varname}')
							elif typeref.isRecord():
								args.append(f'\n/* IN */ const {typeref.impl_name()} *{varname}')
							else:
								args.append(f'\n/* IN */ {typeref.impl_name()} {varname}')
						else:
							if typeref.isArray():
								args.append(f'\n/* {direction} */ {typeref.impl_name()} {varname}')
							else:
								args.append(f'\n/* {direction} */ {typeref.impl_name()} *{varname}')
					ret+=','.join(args)
				ret+=');\n'
				return ret
				
		class CSClient():
			_dataelementref=None
			_operation=None
			_port=None
			_runnables=None
			_assync=False
			def __init__(self,operationref):
				operation=operationref.targetRequiredOperation.ref()
				port=operationref.contextRPort.ref()
				self._assync = isinstance(operationref.parent(),autosar_r4p0.AsynchronousServerCallPoint)
				self._operation=operation
				self._port=port
				self._runnables=RteList()
		class Mode():
			_dataelementref=None
			_modeGroup=None
			_type=None
			_port=None
			_runnables=None
			_mapping=None
			def __init__(self,modeGroup,port,instance):
				self._dataelementref=RteList()
				self._modeGroup=modeGroup
				self._type=TYPE(modeGroup.type.ref(),instance._behavior)
				self._port=port
				self._runnables=defaultdict(RteList)
			
		class Runnable():
			_csServer=None
			_runnable=None
			_taskMappings=None
			_minprio=None
			_maxprio=None
			_tasks=None
			_activatedByRunnables=None
			_exlusiveAreas=None
			_implicits=None
			_pre=None
			_post=None
			def __init__(self,runnable,mappings):
				self._runnable=runnable
				self._taskMappings=mappings
				self._tasks=mappings.RteMappedToTaskRef.select.foreach(lambda e:OsTask.get(e.ref()))
				self._activatedByRunnables=set()
				self._exlusiveAreas=RteList()
				self._implicits={}
				self._pre=""
				self._post=""
			def calcprio(self):
				if self._maxprio is None:
					self._minprio=0
					self._maxprio=0xffffffff
					if self._activatedByRunnables.__len__() > 0:
						RteList(self._activatedByRunnables).calcprio()
						self._maxprio=max((*(e._maxprio for e in self._activatedByRunnables),*self._tasks.prio))
						self._minprio=max((*(e._minprio for e in self._activatedByRunnables),*self._tasks.prio))
					elif self._tasks.__len__() > 0:
						self._minprio=min(self._tasks.prio)
						self._maxprio=max(self._tasks.prio)
			def runsWithinExclArea(self):
				if self._exlusiveAreas.__len__() > 0:
					exclAreaImpl=defaultdict(list)
					#exlusiveAreas=self._exlusiveAreas.select(lambda e:self in e._runnables_protectionNeeded)
					for exlusiveArea in (e for e in self._exlusiveAreas if self in e._runnables_protectionNeeded):
						exclAreaImpl[exlusiveArea._implementation.RteExclusiveAreaImplMechanism.val()].append(exlusiveArea)
					if 'ALL_INTERRUPT_BLOCKING' in exclAreaImpl:
						self._excareaImpl=1
						self._minprio=0xffffffff
					elif 'OS_INTERRUPT_BLOCKING' in exclAreaImpl:
						self._excareaImpl=2
						self._minprio=0xffffffff
					elif 'OS_RESOURCE' in exclAreaImpl:
						self._excareaImpl=3
						self._exclareaResources=set(exclAreaImpl['OS_RESOURCE']._implementation.RteExclusiveAreaOsResourceRef.ref())
						# todo: calc prio from resource
						#self._minprio=0xffffffff
					else:
						self._excareaImpl=0
			def print_def(self):
				if self._csServer is not None:
					return self._csServer.print_def()
				if self._activatedByRunnables or self._taskMappings:
					return f'extern void {self._runnable.symbol.val()}(void);\n'
				return ''
			def print_call(self,command=None):
				if command is None:
					command=self._runnable.symbol.val()+'()'
				res= f'{{\n{self.print_def()}'
				if self._pre !='':
					res+=f'Rte_EnterExclusive();\n{self._pre}Rte_ExitExclusive();\n'
				if self._exlusiveAreas.__len__() > 0:
					sep='\n// \tand '
					res += f'// runs within exclusive area {sep.join(self._exlusiveAreas._exclusiveArea.shortName.val())}\n'
					if self._excareaImpl==1:
						res+=f'SuspendAllInterrupts();\n{command};\nResumeAllInterrupts();\n'
					elif self._excareaImpl==2:
						res+=f'SuspendOSInterrupts();\n{command};\nResumeOSInterrupts();\n'
					elif self._excareaImpl==3:
						resource=exlusiveArea._implementation.RteExclusiveAreaOsResourceRef[0].ref().shortName.val()
						for resource in self._exclareaResources:
							res+=f'GetResource({resource.shortName.val()});\n'
						res+=f'{command};\n'
						for resource in self._exclareaResources:
							res+=f'ReleaseResource({resource.shortName.val()});\n'
					else:
						res+='// all exclusive areas optimized away due to running highest prio\n'
						res+=f'{command};\n'
				else:		
					res+=f'{command};\n'
				if self._post !='':
					res+=f'Rte_EnterExclusive();\n{self._post}Rte_ExitExclusive();\n'
				return res+'}'
		class ExclusiveArea():
			_runnables=None
			_runnables_canEnter=None
			_exclusiveArea=None
			_implementation=None
			_runnables_protectionNeeded=None
			def __init__(self,exclArea,rteSwComponentInstace):
				self._runnables=RteList()
				self._runnables_canEnter=RteList()
				self._exclusiveArea=exclArea
				self._implementation=rteSwComponentInstace.RteExclusiveAreaImplementation.select.findfirst(lambda e:e.RteExclusiveAreaRef.ref() == exclArea,default=ModelNone)
				self._runnables_protectionNeeded=RteList()
			def analyse(self):
				if self._implementation.RteExclusiveAreaImplMechanism==None or self._implementation.RteExclusiveAreaImplMechanism.val()=='COOPERATIVE_RUNNABLE_PLACEMENT':
					# no protection needed
					return
				maxPrio=max(self._runnables._maxprio)
				for runnable in self._runnables:
					if runnable._minprio < maxPrio:
						self._runnables_protectionNeeded.append(runnable)
		class Irv():
			_runnable=None,
			_read=True
			def __init__(self,runnable,read):
				self._runnable=runnable
				self._read=read
		_behavior=None
		_rxdataelements=None
		_txdataelements=None
		_calparams=None
		_irvdataelements=None
		_clients=None
		_servers=None
		_runnables=None
		_exclusiveAreas=None
		_error_codes=None
		_csv=None
		def _set_dataref(self,dataref,dataelements,runnable,accesstype,beh,instance):
			id=(dataref.portPrototype.ref(),dataref.targetDataPrototype.ref())
			dataelement = dataelements.setdefault(id,self.DataElement(dataref.targetDataPrototype.ref(),dataref.portPrototype.ref(),beh,instance))
			dataelement._runnables[accesstype].append(runnable)
		def _set_operationref(self,operationref,operations,runnable):
			operationObj=operationref.targetRequiredOperation.ref()
			id=(operationref.contextRPort.ref(),operationObj)
			operation = operations.setdefault(id,self.CSClient(operationref))
			operation._runnables.append(runnable)
			for error in operationObj.possibleError.ref():
				if error.shortName.val() != 'RTE_E_INVALID':
					self._csv._error_codes[f'RTE_E_{operationObj.parent().shortName.val()}_{error.shortName.val()}'] = error.errorCode.val()
			
		def __init__(self,instance,beh,csv):
			rteSwComponentInstace=rte.RteSwComponentInstance.select.findfirst(lambda e:e.RteSoftwareComponentInstanceRef.ref()==instance)
			self._behavior=beh
			runnables=beh.runnable
			self._runnables={}
			self._rxdataelements={}
			self._txdataelements={}
			self._calparams={}
			self._irvdataelements=defaultdict(RteList)
			self._clients={}
			self._servers={}
			self._modes={}
			self._rxmodes={}
			self._exclusiveAreas={}
			self._csv=csv
			for runnable in runnables:
				events=runnable.references().parent().select.findall(lambda e:e.parent() == beh)
				mappings=rteSwComponentInstace.RteEventToTaskMapping.select.findall(lambda e:e.RteEventRef.ref() in events)
				runnableObj=self.Runnable(runnable,mappings)
				self._runnables[runnable]=runnableObj
				for exlusiveArea in runnable.runsInsideExclusiveArea.ref():
					exlusiveAreaObj=self._exclusiveAreas.setdefault(exlusiveArea, self.ExclusiveArea(exlusiveArea,rteSwComponentInstace))
					exlusiveAreaObj._runnables.append(runnableObj)
					runnableObj._exlusiveAreas.append(exlusiveAreaObj)
				for exlusiveArea in runnable.canEnterExclusiveArea.ref():
					exlusiveAreaObj=self._exclusiveArea.setdefault(exlusiveArea, ExclusiveArea(exlusiveArea,rteSwComponentInstace))
					exlusiveAreaObj._runnables.append(runnableObj)
					exlusiveAreaObj._runnables_canEnter.append(runnableObj)
				for localvar in runnable.readLocalVariable.accessedVariable.localVariable.ref():
					self._irvdataelements[localvar].append(self.Irv(runnable,True))
				for localvar in runnable.writtenLocalVariable.accessedVariable.localVariable.ref():
					self._irvdataelements[localvar].append(self.Irv(runnable,False))
				for dataref in runnable.dataReceivePointByValue.accessedVariable.autosarVariable:
					self._set_dataref(dataref,self._rxdataelements,runnableObj,'dataReceivePointByValue',beh,instance)
				for dataref in runnable.dataReceivePointByArgument.accessedVariable.autosarVariable:
					self._set_dataref(dataref,self._rxdataelements,runnableObj,'dataReceivePointByArgument',beh,instance)
				for dataref in runnable.dataReadAccess.accessedVariable.autosarVariable:
					self._set_dataref(dataref,self._rxdataelements,runnableObj,'dataReadAccess',beh,instance)
				for dataref in runnable.dataSendPoint.accessedVariable.autosarVariable:
					self._set_dataref(dataref,self._txdataelements,runnableObj,'dataSendPoint',beh,instance)
				for dataref in runnable.dataWriteAccess.accessedVariable.autosarVariable:
					self._set_dataref(dataref,self._txdataelements,runnableObj,'dataWriteAccess',beh,instance)
				for calparamref in runnable.parameterAccess.accessedParameter.localParameter.ref():
					calparam=self._calparams.setdefault(calparamref,self.CalParam(calparamref,beh))
					calparam._runnables.append(runnableObj)
				for operationref in runnable.serverCallPoint.SynchronousServerCallPoint.operation:
					self._set_operationref(operationref,self._clients,runnableObj)
				for operationref in runnable.serverCallPoint.AsynchronousServerCallPoint.operation:
					self._set_operationref(operationref,self._clients,runnableObj)
				for operationref in beh.event.OperationInvokedEvent.operation.select.findall(lambda e:e.parent().startOnEvent.ref() == runnable):
					operationObj=operationref.targetProvidedOperation.ref()
					id=(operationref.contextPPort.ref(),operationObj)
					self._servers[id]=self.CSServer(operationObj,operationref.contextPPort.ref(), runnableObj, mappings.select.findfirst(lambda e:e.RteEventRef.ref()==operationref.parent(),default=ModelNone),beh)
					for error in operationObj.possibleError.ref():
						if error.shortName.val() != 'RTE_E_INVALID':
							self._csv._error_codes[f'RTE_E_{operationObj.parent().shortName.val()}_{error.shortName.val()}'] = error.errorCode.val()
				for moderef in beh.event.SwcModeSwitchEvent.mode.select.findall(lambda e:e.parent().startOnEvent.ref() == runnable):
					id=(moderef.contextPort.ref(),moderef.contextModeDeclarationGroupPrototype.ref())
					mode = self._rxmodes.setdefault(id,self.Mode(moderef.contextModeDeclarationGroupPrototype.ref(),moderef.contextPort.ref(),self))
					mode._runnables[(moderef.parent().activation.val().value,moderef.targetModeDeclaration.ref())].append(runnableObj)
					mode._mapping=mappings.select.findfirst(lambda e:e.RteEventRef.ref()==moderef.parent(), ModelNone)
				for modegroupref in runnable.modeSwitchPoint.modeGroup:
					id=(modegroupref.contextPPort.ref(),modegroupref.targetModeGroup.ref())
					mode = self._modes.setdefault(id,self.Mode(modegroupref.targetModeGroup.ref(),modegroupref.contextPPort.ref(),self))
					mode._runnables['modeSwitchPoint'].append(runnableObj)
				for modeAccessPoint in runnable.modeAccessPoint:
					for modegroupref in modeAccessPoint.modeGroup.RModeGroupInAtomicSWCInstanceRef:
						id=(modegroupref.contextRPort.ref(),modegroupref.targetModeGroup.ref())
						mode = self._rxmodes.setdefault(id,self.Mode(modegroupref.targetModeGroup.ref(),modegroupref.contextRPort.ref(),self))
						mode._runnables['modeAccessPoint'].append(runnableObj)
					for modegroupref in modeAccessPoint.modeGroup.PModeGroupInAtomicSwcInstanceRef:
						id=(modegroupref.contextPPort.ref(),modegroupref.targetModeGroup.ref())
						mode = self._modes.setdefault(id,self.Mode(modegroupref.targetModeGroup.ref(),modegroupref.contextPPort.ref(),self))
						mode._runnables['modeAccessPoint'].append(runnableObj)
	_csv = None
	_instances=None
	_internal_behavior=None
	_error_codes=None
	def __init__(self, csv):
		self._csv = csv
		self._instances={}
		self._error_codes={}
	def add(self,instance, behavior):
		self._instances[instance] = self.Instance(instance, behavior, self)
		self._internal_behavior=behavior
	def Write_Rte_SWC_type_h(self):
		c = CWriter(f'Rte_{self._csv.shortName.val()}_Type.h')
		c << f'''#ifndef RTE_{self._csv.shortName.val().upper()}_TYPE_H
#define RTE_{self._csv.shortName.val().upper()}_TYPE_H

#include "Rte_Type.h"

'''
		interfaces=self._csv.port.PPortPrototype.providedInterface.ref() + self._csv.port.RPortPrototype.requiredInterface.ref()
		reftypes=list(interfaces.dataElement.type.ref())
		reftypes.extend(interfaces.operation.argument.type.ref())
		reftypes.extend(self._internal_behavior.arTypedPerInstanceMemory.type.ref())
		for pimtype in set(self._internal_behavior.perInstanceMemory.typeDefinition.val()):
			try:
				reftypes.append(next((t for t in autosar_r4p0.ImplementationDataType.instances() if t.shortName.val() == pimtype)))
			except:
				pass
		# variable data prototypes
		reftypes.extend(self._internal_behavior.arTypedPerInstanceMemory.type.ref())
		reftypes.extend(self._internal_behavior.explicitInterRunnableVariable.type.ref())
		reftypes.extend(self._internal_behavior.implicitInterRunnableVariable.type.ref())
		reftypes.extend(self._internal_behavior.staticMemory.type.ref())
		# params
		reftypes.extend(self._internal_behavior.constantMemory.type.ref())
		reftypes.extend(self._internal_behavior.perInstanceParameter.type.ref())
		reftypes.extend(self._internal_behavior.sharedParameter.type.ref())
		# port api options
		reftypes.extend(self._internal_behavior.portAPIOption.portArgValue.valueType.ref())
		# data type mappings
		reftypes.extend(self._internal_behavior.dataTypeMapping.ref().dataTypeMap.applicationDataType.ref())
		reftypes.extend(self._internal_behavior.dataTypeMapping.ref().dataTypeMap.implementationDataType.ref())
		#constant mappings
		#reftypes.extend(self._internal_behavior.constantValueMapping.ref().dataTypeMap.foreach(lambda e:(e.applicationDataType.ref(),e.implementationDataType.ref())))
		#mode mappings
		reftypes.extend(self._internal_behavior.dataTypeMapping.ref().modeRequestTypeMap.implementationDataType.ref())
		
		refs=set()
		for reftype in reftypes:
			if reftype.swDataDefProps.compuMethod.ref().category.val()=='TEXTTABLE' and reftype not in refs:
				refs.add(reftype)
				t=TYPE(reftype,self._internal_behavior)
				for scale in reftype.swDataDefProps.compuMethod.ref().compuInternalToPhys.compuScale:
					if scale.symbol!=None:
						name = scale.symbol.val()
					elif scale.compuConst.vt!=None:
						name = scale.compuConst.vt.val()
					elif scale.shortLabel!=None:
						name = scale.shortLabel.val()
					else:
						continue
					c << f'''#ifndef {name}
						#define {name} (({t.name()}){t.print_val(scale.lowerLimit.val())})
						#endif // {name}
						'''
		# get all the used mode ports
		refmodedeclgroups=set(interfaces.modeGroup.type.ref())
		for modedeclgroup in refmodedeclgroups:
			# should use sorted index if category is ALPHABETIC_ORDER and specified value if EXPLICIT_ORDER
			modetype=TYPE(modedeclgroup,self._internal_behavior)
			# cannot find that this type should be generated but necessary to get example to run remove?
			c << f'''
				#ifndef RTE_MODETYPE_{modedeclgroup.shortName.val()}
				#define RTE_MODETYPE_{modedeclgroup.shortName.val()}
				typedef {modetype.impl_name()} Rte_ModeType_{modedeclgroup.shortName.val()};
				#endif'''
			for i,mode in enumerate(modedeclgroup.modeDeclaration.select.sorted(lambda e:e.shortName.val())):
				name=f'RTE_MODE_{modedeclgroup.shortName.val()}_{mode.shortName.val()}'
				c << f'''#ifndef {name}
					#define {name} {i}
					#endif'''
			c << f'''#ifndef RTE_TRANSITION_{modedeclgroup.shortName.val()}
				#define RTE_TRANSITION_{modedeclgroup.shortName.val()} {len(modedeclgroup.modeDeclaration)}
				#endif'''

		c << f'''
			#endif // RTE_{self._csv.shortName.val().upper()}_TYPE_H
			'''
		c.close()
		
	def Write_Rte_SWC_h(self):
		c = CWriter(f'Rte_{self._csv.shortName.val()}.h')
		c << f'''#ifndef RTE_{self._csv.shortName.val().upper()}_H
#define RTE_{self._csv.shortName.val().upper()}_H

#ifdef RTE_APPLICATION_HEADER_FILE
#error Multiple application header files included.
#endif // RTE_APPLICATION_HEADER_FILE
#define RTE_APPLICATION_HEADER_FILE

#ifdef __cplusplus
extern "C" {{
#endif

#include "Rte_{self._csv.shortName.val()}_Type.h"
#include <Os.h>
#include <Com.h>

#define Rte_EnterExclusive()	SuspendAllInterrupts()
#define Rte_ExitExclusive()		ResumeAllInterrupts()
'''
		used_runnables = self._internal_behavior.runnable
		res = ''
		for i,runnable in enumerate(used_runnables.shortName.val()):
			if i == 0:
				res = f'#if  !defined(RTE_RUNNABLEAPI_{runnable})'
			else:
				res += f' && !defined(RTE_RUNNABLEAPI_{runnable})'
			if i == len(used_runnables)-1:
				res += '''
	#define RTE_RUNNABLEAPI
#else
	#undef RTE_APPLICATION_HEADER_FILE
#endif
'''
		c << res
		
		#application data types
		c << '\n// define all used application data types'
		for map in self._internal_behavior.dataTypeMapping.ref().dataTypeMap:
			if map.applicationDataType.val().split("/")[-1] != map.implementationDataType.ref().shortName.val():
				c << f'#define {map.applicationDataType.val().split("/")[-1]} {map.implementationDataType.ref().shortName.val()}'

		c << '\n// Define all initial values'
		for port in self._csv.port.PPortPrototype:
			for initval in port.providedComSpec.NonqueuedSenderComSpec.select.findall(lambda e:e.dataElement.ref().type.ref().category.val() in ('VALUE','BOOLEAN')).initValue:
				type_=TYPE(initval.parent().dataElement.ref().type.ref(),self._internal_behavior)
				c << f'#define Rte_InitValue_{port.shortName.val()}_{initval.parent().dataElement.ref().shortName.val()} {type_.VALUE2str(initval)}' #<suffix>
		for port in self._csv.port.RPortPrototype:
			for initval in port.requiredComSpec.NonqueuedReceiverComSpec.select.findall(lambda e:e.dataElement.ref().type.ref().category.val() in ('VALUE','BOOLEAN')).initValue:
				type_=TYPE(initval.parent().dataElement.ref().type.ref(),self._internal_behavior)
				c << f'#define Rte_InitValue_{port.shortName.val()}_{initval.parent().dataElement.ref().shortName.val()} {type_.VALUE2str(initval)}' #<suffix>
		
		c << '\n// Define all Application error codes'
		for error,val in self._error_codes.items():
			c << f'#define {error} {val}'
		
		c << '\n// Define all PIM types'
		pimtypes = {}
		for pim in self._internal_behavior.perInstanceMemory:
			pimtypes[pim.type.val()] = pim.typeDefinition.val()
		for type,typedefinition in pimtypes.items():
			c << f'\ntypedef Rte_PimType_{self._csv.shortName.val()}_{type} {type};'
			Rte_type_h.AddPimType(f'typedef {typedefinition} Rte_PimType_{self._csv.shortName.val()}_{type};')
		
		c << '\n// Define all PIM access functions'
		for pim in self._internal_behavior.perInstanceMemory:
			name=f'Rte_Pim_{self._internal_behavior.shortName.val()}_{pim.shortName.val()}'
			c << f'''static inline {pim.type.val()}* Rte_Pim_{pim.shortName.val()}(void) {{
				extern {pim.type.val()} {name};
				return &{name};
			}}'''
		for pim in self._internal_behavior.arTypedPerInstanceMemory:
			_type=TYPE(pim.type.ref(),self._internal_behavior)
			name=f'Rte_Pim_{self._internal_behavior.shortName.val()}_{pim.shortName.val()}'
			if _type.isArray():
				c << f'''static inline {_type.element_type().name()}* Rte_Pim_{pim.shortName.val()}(void) {{
					extern {_type.name()} {name};
					return {name};
				}}'''
			else:
				c << f'''static inline {_type.name()}* Rte_Pim_{pim.shortName.val()}(void) {{
					extern {_type.name()} {name};
					return &{name};
				}}'''
		
		# read and write functions
		if self._internal_behavior.supportsMultipleInstantiation.val() == True:
			assert 0,'multiple instation not supported'
		else:
			instanceobj,instance=self._instances.items().__iter__().__next__()
			
			for runnable in instance._runnables.values():
				c << runnable.print_def()
			for localvar,accesslist in instance._irvdataelements.items():
				vartype=TYPE(localvar.type.ref(),instance._behavior)
				if localvar.binding().name()=='implicitInterRunnableVariable':
					maxprio=max((instance._runnables[runnable]._maxprio for runnable in accesslist._runnable))
					for irv in accesslist:
						irv_runnable=instance._runnables[irv._runnable]
						needsprotection=irv_runnable._minprio < maxprio
						irvvarname=f'Rte_Irv_{instanceobj.shortName.val()}_{localvar.shortName.val()}'
						if needsprotection:
							varname=f'Rte_Implicit_Irv_{irv._runnable.shortName.val()}_{instanceobj.shortName.val()}_{localvar.shortName.val()}'
							for runnable in accesslist._runnable:
								instance._runnables[runnable]._implicits[varname] = vartype
							decl = f'''extern {vartype.impl_name()} {varname};
							extern {vartype.impl_name()} {irvvarname};
							'''
							if irv._read:
								irv_runnable._pre+=decl+vartype.copy(varname,vartype,irvvarname)
							else:
								irv_runnable._post+=decl+vartype.copy(irvvarname,vartype,varname)
						else:
							varname=irvvarname
						res = RunnableApiOpen([irv._runnable])
						if irv._read:
							if vartype.isPrimitive():
								rettype=vartype.name()
							elif vartype.isArray():
								rettype='const ' + vartype.element_type().name()+'*'
							elif vartype.isRecord():
								rettype='const ' + vartype.name()+'*'
							else:
								rettype='error not supported type category'
							res+=f'static inline {rettype} Rte_IrvIRead_{irv._runnable.shortName.val()}_{localvar.shortName.val()}(void) {{\n'
							res+=f'extern {vartype.name()} {varname};\n'
							if vartype.isRecord():
								res+=f'return &{varname};\n}}\n'
							else:
								res+=f'return {varname};\n}}\n'
						else:
							res+=f'static inline void Rte_IrvWrite_{irv._runnable.shortName.val()}_{localvar.shortName.val()}({vartype.name()} data) {{\n'
							res+=f'extern {vartype.name()} {varname};\n'
							res+=vartype.copy(varname,vartype,'data')+'}\n'
						res+=RunnableApiClose()
						c << res
							
				else:
					atomic=vartype.isAtomic()
					if not atomic:
						readers=accesslist.select.findall(lambda e:e._read)
						maxreadprio=max(readers._runnable._maxprio)
						writers=accesslist.select.findall(lambda e:e._read)
						maxwriteprio=max(writers._runnable._maxprio)
					#return minprio < maxprio
					for irv in accesslist:
						res = RunnableApiOpen([irv._runnable])
						if irv._read:
							if not atomic:
								needsprotection=irv._runnable._minprio < maxwriteprio
							else:
								needsprotection=False
							if vartype.isPrimitive():
								res+=f'static inline {vartype.name()} Rte_IrvRead_{irv._runnable.shortName.val()}_{localvar.shortName.val()}(void) {{\n'
								res+=f'extern {vartype.name()} Rte_Irv_{instanceobj.shortName.val()}_{localvar.shortName.val()};\n'
								if needsprotection:
									res+='Rte_EnterExclusive();\n'
								res+=f'{vartype.name()} ret = Rte_Irv_{instanceobj.shortName.val()}_{localvar.shortName.val()};\n'
								if needsprotection:
									res+='Rte_ExitExclusive();\n'
								res+='return ret;\n'
							else:
								if vartype.isArray():
									rettype=vartype.element_type().name()+'*'
								elif vartype.isRecord():
									rettype=vartype.name()+'*'
								else:
									rettype='error not supported type category'
								res+=f'static inline void Rte_IrvRead_{irv._runnable.shortName.val()}_{localvar.shortName.val()}({rettype} data) {{\n'
								to.do()
						else:
							if not atomic:
								needsprotection=irv._runnable._minprio < maxreadprio
							else:
								needsprotection=False
							res+=f'static inline void Rte_IrvWrite_{irv._runnable.shortName.val()}_{localvar.shortName.val()}({vartype.name()} data) {{\n'
							res+=f'extern {vartype.name()} Rte_Irv_{instanceobj.shortName.val()}_{localvar.shortName.val()};\n'
							if needsprotection:
								res+='Rte_EnterExclusive();\n'
							res+=f'Rte_Irv_{instanceobj.shortName.val()}_{localvar.shortName.val()} = data;\n'
							if needsprotection:
								res+='Rte_ExitExclusive();\n'
						res+='}\n'
						res+=RunnableApiClose()
						c << res
					
				#(read,runnable)
			
			for id, dataelement in instance._rxdataelements.items():
				runnables = dataelement._runnables['dataReadAccess']
				for runnable in runnables:
					res = RunnableApiOpen([runnable._runnable])
					if dataelement._type.isPrimitive():
						rettype=dataelement._type.name()
					elif dataelement._type.isArray():
						rettype='const ' + dataelement._type.element_type().name()+'*'
					elif dataelement._type.isRecord():
						rettype='const ' + dataelement._type.name()+'*'
					else:
						rettype='error not supported type category'
					res+=f'static inline {rettype} Rte_IRead_{runnable._runnable.shortName.val()}_{id[0].shortName.val()}_{id[1].shortName.val()}(void) {{\n'
					if dataelement._dataelementref.__len__() == 0 and dataelement._comSignalRef.__len__() == 0:
						#unconnected
						res+=f'return ({dataelement._type.name()}){dataelement._type.VALUE2str(dataelement._rxcomspec.initValue)};\n}}\n'
					else:
						if dataelement._comSignalRef.__len__() > 0 or runnable._minprio < max((*(runnable._maxprio for d in dataelement._dataelementref for runnables in d._runnables.values() for runnable in runnables),runnable._maxprio)) or dataelement._type.isArray():
							# protected variable
							vartype=dataelement._type
							varname=f'Rte_Implicit_SR_{runnable._runnable.shortName.val()}_{runnable._runnable.parent().parent().shortName.val()}_{id[0].shortName.val()}_{id[1].shortName.val()}'
							res+=f'extern {vartype.name()} {varname};\n'
							res+=f'return {varname};\n}}\n'
						else:
							# no need for access protection
							res+=f' {dataelement._type.impl_name()} temp;\n'
							res+=dataelement.print_read('&temp')
							res+='return temp;\n}\n'
					res+=RunnableApiClose()
					c << res
				runnables = dataelement._runnables['dataReceivePointByValue']._runnable
				if len(runnables) > 0:
					dataelement=instance._rxdataelements[id]
					res = RunnableApiOpen(runnables)
					res+=f'''static inline {dataelement._type.name()} Rte_DRead_{id[0].shortName.val()}_{id[1].shortName.val()}(void) {{
	extern {dataelement._type.name()} Rte_CDATA_{id[0].shortName.val()}_{id[1].shortName.val()};
	return Rte_CDATA_{id[0].shortName.val()}_{id[1].shortName.val()};
}}
'''
					res+=RunnableApiClose()
					c << res

#			for id, dataelement in instance._rxdataelements.items():
				runnables = dataelement._runnables['dataReceivePointByArgument']._runnable
				if len(runnables) > 0:
					res = RunnableApiOpen(runnables)
					res+=f'static inline Std_ReturnType Rte_Read_{id[0].shortName.val()}_{id[1].shortName.val()}({dataelement._type.name()} {"" if dataelement._type.isArray() else "*"}data) {{\n'
					if dataelement._dataelementref.__len__() == 0 and dataelement._comSignalRef.__len__() == 0:
						#unconnected
						res+=f'static const {dataelement._type.name()} init = {dataelement._type.VALUE2str(dataelement._rxcomspec.initValue)};\n'
						res+=dataelement._type.copy('*data',dataelement._type, 'init')
						res+='return RTE_E_UNCONNECTED;\n}\n'
					else:
						needsprotection= dataelement.needProtection()
						if needsprotection:
							res+='Rte_EnterExclusive();\n'
						res+=dataelement.print_read('data')
						if needsprotection:
							res+='Rte_ExitExclusive();\n'
						res+='return RTE_E_OK;\n}\n'
					res+=RunnableApiClose()
					c << res
				
			for id, dataelement in instance._txdataelements.items():
				runnables = dataelement._runnables['dataWriteAccess']
				for runnable in runnables:
					res = RunnableApiOpen([runnable._runnable])
					res+=f'static inline Std_ReturnType Rte_IWrite_{runnable._runnable.shortName.val()}_{id[0].shortName.val()}_{id[1].shortName.val()}( const {dataelement._type.name()} {"*" if dataelement._type.isRecord() else ""}data) {{\n'
					if dataelement._comSignalRef.__len__() > 0 or runnable._minprio < max((*(runnable._maxprio for d in dataelement._dataelementref for runnables in d._runnables.values() for runnable in runnables), runnable._maxprio)):
						# protected variable
						pass
					else:
						res+=dataelement.print_write('data')
					res+='return RTE_E_OK;\n}\n'
					res+=RunnableApiClose()
					c << res

				runnables = dataelement._runnables['dataSendPoint']._runnable
				if len(runnables) > 0:
					res = RunnableApiOpen(runnables)
					res+=f'static inline Std_ReturnType Rte_Write_{id[0].shortName.val()}_{id[1].shortName.val()}(const {dataelement._type.name()} {"*" if dataelement._type.isRecord() else ""}data) {{\n'
					needsprotection= dataelement.needProtection()
					if needsprotection:
						res+='Rte_EnterExclusive();\n'
					res+=dataelement.print_write('data')
					if needsprotection:
						res+='Rte_ExitExclusive();\n'
					res+='return RTE_E_OK;\n}\n'
					res+=RunnableApiClose()
					c << res
			for calparamobj,calparam in instance._calparams.items():
				res=RunnableApiOpen(calparam._runnables._runnable)
				if calparam._type.isPrimitive():
					rettype=calparam._type.name()
				elif calparam._type.isArray():
					rettype=f'const {calparam._type.element_type().name()} *'
				elif calparam._type.isRecord():
					rettype='const ' + calparam._type.name()+'*'
				else:
					rettype='error not supported type category'
				if calparamobj.binding().name() == 'sharedParameter':
					name=f'Rte_CalPrm_Rom_{self._csv.shortName.val()}_{calparamobj.shortName.val()}'
				else:
					name=f'Rte_CalPrm_Rom_{instanceobj.shortName.val()}_{calparamobj.shortName.val()}'
				res+=f'static inline {rettype} Rte_CData_{calparamobj.shortName.val()}(void) {{\n'
				res+=f'extern {calparam._type.name()} {name};\n'
				res+=f'return {name};\n}}\n'
				res+=RunnableApiClose()
				c << res
			for id,operation in instance._clients.items():
				res = RunnableApiOpen(operation._runnables._runnable)
				arglist=RteList()
				callarglist=RteList()
				for arg in id[1].argument:
					argtype=TYPE(arg.type.ref(),instance._behavior)
					callarglist.append((argtype,arg.shortName.val()))
					arglist.append(f'\n\t/* {arg.direction.val().value} */ {"const " if arg.direction.val().value=="IN" else ""}{argtype.name()} ' +
						('*' if not arg.direction.val().value=="IN" and not argtype.isArray() or arg.direction.val().value=="IN" and argtype.isRecord() else '') +
						arg.shortName.val())
				args=','.join(arglist)
				res += f'static inline Std_ReturnType Rte_Call_{id[0].shortName.val()}_{id[1].shortName.val()}({args}) {{\n'
				if operation._dataelementref is None:
					for argtype,argname in callarglist:
    						res += f'(void){argname}; // argument not used\n'
					res += 'return RTE_E_UNCONNECTED;\n}\n'
				elif not operation._dataelementref._mapping.RteMappedToTaskRef.ref()==None:
					fname=f'Rte_Call_{self._csv.shortName.val()}_{id[0].shortName.val()}_{id[1].shortName.val()}'
					res += f'''extern Std_ReturnType {fname}({args});
						return {fname}({', '.join(id[1].argument.shortName.val())});
					}}
					'''
				else:
					op=operation._dataelementref
					intbeh=op._runnable._runnable.parent()
					opname=op._runnable._runnable.symbol.val()
					portApiOption=intbeh.portAPIOption.select.findall(lambda e:e.port.ref() == operation._dataelementref._port)
					unnamedarg=0
					runnableargs=RteList()
					for arg in portApiOption.portArgValue:
						type_=TYPE(arg.valueType.ref(),intbeh)
						runnableargs.append(type_.VALUE2str(arg.value[0]))
						unnamedarg+=1
					for arg, callarg in zip(op._operation.argument, callarglist):
						argtype=TYPE(arg.type.ref(),intbeh)
						argname=arg.shortName.val()
						if argtype.ScalingNeeded(callarg[0]):
							res += f'{argtype.impl_name()} arg_{unnamedarg};\n'
							res+=argtype.copy(f'arg_{unnamedarg}',callarg[0],callarg[1])
							runnableargs.append(f'arg_{unnamedarg}')
							unnamedarg+=1
						else:
							runnableargs.append(callarg[1])
					voidtype=op._operation.possibleError==None
					res+='Std_ReturnType ret = RTE_E_OK;\n'
					res+=op._runnable.print_call(f'{"ret = " if not voidtype else ""}{opname}({", ".join(runnableargs)})')
					res+='\nreturn ret;\n}\n'
				res+=RunnableApiClose()
				c << res
			
			for id,mode in instance._modes.items():
				res = RunnableApiOpen(mode._runnables['modeSwitchPoint']._runnable)
				name=f'{id[0].shortName.val()}_{id[1].shortName.val()}'
				res += f'static inline Std_ReturnType Rte_Switch_{name}({mode._type.impl_name()} mode){{\n'
				if mode._dataelementref.__len__() > 0:
					res+=f'''extern Std_ReturnType Rte_Switch_{self._csv.shortName.val()}_{name}({mode._type.impl_name()} mode);
						return Rte_Switch_{self._csv.shortName.val()}_{name}(mode);
					}}
					'''
				else:
					res+='''// unconnected
					return RTE_E_OK;
					}
					'''
				res+=RunnableApiClose()
				c << res
			
			for id,mode in {**instance._rxmodes, **instance._modes}.items():
				if 'modeAccessPoint' not in mode._runnables:
					continue
				res = RunnableApiOpen(mode._runnables['modeAccessPoint']._runnable)
				res+=f'static inline {mode._type.impl_name()} Rte_Mode_{id[0].shortName.val()}_{id[1].shortName.val()}(void) {{\n'
				if mode._dataelementref.__len__() == 0:
					#unconnected
					if not mode._modeGroup.type.ref().initialMode.val():
						initialMode = '0'
					else:
						initialMode=f'RTE_MODE_{mode._modeGroup.type.ref().shortName.val()}_{mode._modeGroup.type.ref().initialMode.val().split("/")[-1]}'
					res+=f'''return {initialMode};
					}}
					'''
				else:
					varname = f'Rte_mode_current_{mode._dataelementref[0]._port.parent().shortName.val()}_{mode._dataelementref[0]._port.shortName.val()}_{mode._dataelementref[0]._port.providedInterface.ref().modeGroup[0].shortName.val()}'
					res += f'''extern {mode._dataelementref[0]._type.impl_name()} {varname};
					return ({mode._type.impl_name()}){varname};
					}}
					'''
				res+=RunnableApiClose()
				c << res
					
				
		# per runnable med event: gen
		
		#cleanup in the end
		for runnable in used_runnables.shortName.val():
			c << f'''#ifdef RTE_RUNNABLEAPI_{runnable}
	#undef RTE_RUNNABLEAPI_{runnable}
#endif'''
		c << f'''#ifdef RTE_RUNNABLEAPI
	#undef RTE_RUNNABLEAPI
#endif
#ifdef __cplusplus
}} // extern "C"
#endif
#endif // RTE_{self._csv.shortName.val().upper()}_H
'''
		c.close()

def GenRte():
	Rte_type_h = _Rte_type_h()

	csvs = {}
	# add all instances
	for instmap in extract.mapping.swImplMapping:
		behavior = instmap.componentImplementation.ref().behavior.ref()
		swc = behavior.parent()
		for inst in instmap.component.select.findall(lambda e:e.contextComposition.ref() == rootcomposition).targetComponent.ref():
			if swc not in csvs:
				csvs[swc] = CSV(swc)
			csvs[swc].add(inst,behavior)

	# map the ports
	for conn in rootcomposition.softwareComposition.ref().connector.AssemblySwConnector:
		provider_port=conn.provider.targetPPort.ref()
		requester_port=conn.requester.targetRPort.ref()
		provider_instance=conn.provider.contextComponent.ref()
		provider_csv=csvs[provider_instance.type.ref()]
		provider_inst_obj=provider_csv._instances[provider_instance]
		requester_instance=conn.requester.contextComponent.ref()
		requester_csv=csvs[requester_instance.type.ref()]
		requester_inst_obj=requester_csv._instances[requester_instance]
		if isinstance(provider_port.providedInterface.ref(),autosar_r4p0.SenderReceiverInterface):
			for dataelement in provider_port.providedInterface.ref().dataElement:
				if (provider_port,dataelement) in provider_inst_obj._txdataelements:
					# search for requester port
					requester_dataelement=None
					if dataelement in conn.mapping.ref().dataMapping.firstDataPrototype.ref():
						requester_dataelement=conn.mapping.ref().dataMapping.select.findfirst(lambda self:self.firstDataPrototype.ref()==dataelement).secondDataPrototype.ref()
					elif dataelement in conn.mapping.ref().dataMapping.secondDataPrototype.ref():
						requester_dataelement=conn.mapping.ref().dataMapping.select.findfirst(lambda self:self.secondDataPrototype.ref()==dataelement).firstDataPrototype.ref()
					else:
						for (rport,relement) in requester_inst_obj._rxdataelements.keys():
							if rport == requester_port and relement.shortName.val() == dataelement.shortName.val():
								requester_dataelement=relement
								break
					if requester_dataelement is not None and (requester_port,requester_dataelement) in requester_inst_obj._rxdataelements:
						rxdataelem=requester_inst_obj._rxdataelements[(requester_port,requester_dataelement)]
						txdataelem=provider_inst_obj._txdataelements[(provider_port,dataelement)]
						rxdataelem._dataelementref.append(txdataelem)
						txdataelem._dataelementref.append(rxdataelem)
		elif isinstance(provider_port.providedInterface.ref(),autosar_r4p0.ClientServerInterface):
			for operation in provider_port.providedInterface.ref().operation:
				if (provider_port,operation) in provider_inst_obj._servers:
					# search for requester port
					client_op=None
					if operation in conn.mapping.ref().operationMapping.firstOperation.ref():
						client_op=conn.mapping.ref().operationMapping.select.findfirst(lambda self:self.firstOperation.ref()==operation).secondOperation.ref()
					elif operation in conn.mapping.ref().operationMapping.secondOperation.ref():
						client_op=conn.mapping.ref().operationMapping.select.findfirst(lambda self:self.secondOperation.ref()==operation).firstOperation.ref()
					else:
						for (rport,rop) in requester_inst_obj._clients.keys():
							if rport == requester_port and rop.shortName.val() == operation.shortName.val():
								client_op=rop
								break
					if client_op is not None and (requester_port,client_op) in requester_inst_obj._clients:
						rxdataelem=requester_inst_obj._clients[(requester_port,client_op)]
						txdataelem=provider_inst_obj._servers[(provider_port,operation)]
						rxdataelem._dataelementref=txdataelem
						txdataelem._dataelementref.append(rxdataelem)
						if txdataelem._mapping.RteMappedToTaskRef.ref()==None:
							txdataelem._runnable._activatedByRunnables.update(rxdataelem._runnables)
		elif isinstance(provider_port.providedInterface.ref(),autosar_r4p0.ModeSwitchInterface):
			#for operation in provider_port.providedInterface.ref().operation:
			modegroup=provider_port.providedInterface.ref().modeGroup
			if (provider_port,modegroup) in provider_inst_obj._modes:
				# search for requester port
				modeclient=None
				for (rport,rop) in requester_inst_obj._rxmodes.keys():
					if rport == requester_port and rop.shortName.val() == modegroup.shortName.val():
						modeclient=rop
						break
				if modeclient is not None and (requester_port,modeclient) in requester_inst_obj._rxmodes:
					rxdataelem=requester_inst_obj._rxmodes[(requester_port,modeclient)]
					txdataelem=provider_inst_obj._modes[(provider_port,modegroup)]
					rxdataelem._dataelementref.append(txdataelem)
					txdataelem._dataelementref.append(rxdataelem)
					if rxdataelem._mapping==None or rxdataelem._mapping.RteMappedToTaskRef.ref()==None:
						for runnables in rxdataelem._runnables.values():
							# is this correct for all types of mode receptions?
							#runnables.update+=txdataelem._runnables['modeSwitchPoint']
							for r in runnables:
								r._activatedByRunnables.update(txdataelem._runnables['modeSwitchPoint'])
						#RteList(rxdataelem._runnables.values())._activatedByRunnables.update(txdataelem._runnables['modeSwitchPoint'])
			#provider_port.providedInterface.
	for mapping in extract.mapping.dataMapping:
		port=mapping.dataElement.contextPort.ref()
		instance=mapping.dataElement.contextComponent[0].ref()
		csv=csvs[instance.type.ref()]
		inst_obj=csv._instances[instance]
		dataelement=mapping.dataElement.targetDataPrototype.ref()
		i=(port,dataelement)
		if i in inst_obj._txdataelements:
			dataelement=inst_obj._txdataelements[i]
			systemsig=mapping.systemSignal.ref()
			isig=systemsig.references().parent().select.findall(lambda e:isinstance(e,autosar_r4p0.ISignal))
			isigMapping=isig.select.foreach(lambda e:e.references()).parent().select.findall(lambda e:isinstance(e,autosar_r4p0.ISignalToIPduMapping))
			comSig=isigMapping.select.foreach(lambda e:e.references()).parent().parent().select.findfirst(lambda e:e.parent().parent()==com,default=ModelNone)
			if comSig==None:
				print(f'Error 001: Cannot find Com signal for referenced system signal {mapping.systemSignal.val()}')
				continue
			isig=comSig.ComSystemTemplateSystemSignalRef.ref().iSignal.ref()
			dataelement._comSignalRef.append((systemsig,isig,comSig))
		elif i in inst_obj._rxdataelements:
			dataelement=inst_obj._rxdataelements[i]
			systemsig=mapping.systemSignal.ref()
			isig=systemsig.references().parent().select.findall(lambda e:isinstance(e,autosar_r4p0.ISignal))
			isigMapping=isig.select.foreach(lambda e:e.references()).parent().select.findall(lambda e:isinstance(e,autosar_r4p0.ISignalToIPduMapping))
			comSig=isigMapping.select.foreach(lambda e:e.references()).parent().parent().select.findfirst(lambda e:e.parent().parent()==com,default=ModelNone)
			if comSig==None:
				print(f'Error 001: Cannot find Com signal for referenced system signal {mapping.systemSignal.val()}')
				continue
			isig=comSig.ComSystemTemplateSystemSignalRef.ref().iSignal.ref()
			dataelement._comSignalRef.append((systemsig,isig,comSig))
		else:
			print(f'Error 002: Cannot find port mapped signal {i}')

	# start with runnable prio analysis
	for csv in csvs.values():
		for instanceobj,instance in csv._instances.items():
			for runnable in instance._runnables.values():
				runnable.calcprio()
	# then act upon the prio analysis
	for csv in csvs.values():
		for instanceobj,instance in csv._instances.items():
			for exclarea in instance._exclusiveAreas.values():
				exclarea.analyse()
			for runnable in instance._runnables.values():
				runnable.runsWithinExclArea()
			for id,txdataelem in instance._txdataelements.items():
				txstorage=False
				if txdataelem._dataelementref.__len__() > 0:
					for rxdataelem in txdataelem._dataelementref:
						if rxdataelem._dataelementref.__len__() > 1:
							rxdataelem._storeLocal=True
						else:
							txstorage=True
				elif txdataelem._comSignalRef.__len__() == 0:
					txstorage=True
				txdataelem._storeLocal=txstorage
				for runnable in txdataelem._runnables['dataWriteAccess']:
					if txdataelem._comSignalRef.__len__() > 0 or runnable._minprio < max((*(runnable._maxprio for d in txdataelem._dataelementref for runnables in d._runnables.values() for runnable in runnables), runnable._maxprio)):
						# protected variable
						vartype=txdataelem._type
						varname=f'Rte_Implicit_SR_{runnable._runnable.shortName.val()}_{runnable._runnable.parent().parent().shortName.val()}_{id[0].shortName.val()}_{id[1].shortName.val()}'
						runnable._implicits[varname]=vartype
						runnable._post+=f'extern {vartype.impl_name()} {varname};\n'
						runnable._post+=txdataelem.print_write(varname)
			for id,dataelement in instance._rxdataelements.items():
				for runnable in dataelement._runnables['dataReadAccess']:
					if dataelement._dataelementref.__len__() == 0 and dataelement._comSignalRef.__len__() == 0:
						#unconnected
						pass
					else:
						if dataelement._comSignalRef.__len__() > 0 or runnable._minprio < max((*(runnable._maxprio for d in dataelement._dataelementref for runnables in d._runnables.values() for runnable in runnables),runnable._maxprio)) or dataelement._type.isArray():
							# protected variable
							vartype=dataelement._type
							varname=f'Rte_Implicit_SR_{runnable._runnable.shortName.val()}_{runnable._runnable.parent().parent().shortName.val()}_{id[0].shortName.val()}_{id[1].shortName.val()}'
							runnable._implicits[varname]=vartype
							if not vartype.isArray():
								varnameptr='&'+varname
							else:
								varnameptr=varname
							runnable._pre+=f'''extern {vartype.impl_name()} {varname};
											{dataelement.print_read(varnameptr)}'''

	for csv in csvs.values():
		csv.Write_Rte_SWC_h()
		csv.Write_Rte_SWC_type_h()

	ci = CWriter('Rte_internal.h')
	ci << '''//Dummy file used for external declarations of variables and functions used by Rte. This file shall only be included in Rte.c
	'''
	c = CWriter('Rte.c')
	c << '''#include <Rte.h>
	#include <Os.h>
	#include <Com.h>
	#include "Rte_internal.h"

	#define Rte_EnterExclusive()	SuspendAllInterrupts()
	#define Rte_ExitExclusive()		ResumeAllInterrupts()
	'''
	tasks=defaultdict(RteList)
	# identify sender receiver storage location
	for csv in csvs.values():
		for instanceobj,instance in csv._instances.items():
			c << f'\n// instance: {instanceobj.shortName.val()}'
			c << '// IRV buffers'
			for irv in instance._irvdataelements:
				irvType=TYPE(irv.type.ref(),instance._behavior)
				Rte_Irv = f'{irvType.impl_name()} Rte_Irv_{instanceobj.shortName.val()}_{irv.shortName.val()}'
				ci << f'extern {Rte_Irv};'
				c << f'{Rte_Irv};'
			c << '// SR buffers'
			for txdataelem in instance._txdataelements.values():
				if txdataelem._storeLocal == True:
					c << f'{txdataelem._type.impl_name()} {txdataelem._buf_name};'
			for rxdataelem in instance._rxdataelements.values():
				if rxdataelem._storeLocal == True:
					c << f'{rxdataelem._type.impl_name()} {rxdataelem._buf_name};'
							
			c << '// implicit buffers'
			for runnable in instance._runnables.values():
				for implicit,type in runnable._implicits.items():
					c << f'{type.impl_name()} {implicit};'
			c << '// pim buffers'
			for pim in instance._behavior.perInstanceMemory:
				if pim.initValue != None:
					init=f' = {pim.initValue.val()}'
				else:
					init=''
				c << f'Rte_PimType_{csv._csv.shortName.val()}_{pim.type.val()} Rte_Pim_{instance._behavior.shortName.val()}_{pim.shortName.val()}{init};'
			for pim in instance._behavior.arTypedPerInstanceMemory:
				_type=TYPE(pim.type.ref(),instance._behavior)
				if pim.initValue!=None:
					init=f' = {_type.VALUE2str(pim.initValue)}'
				else:
					init=''
				# todo: save variable declaration once to be used on multiple places
				postdecl=''
				if pim.swDataDefProps.swAddrMethod:
					# todo: don't think that VAR should be included here
					c << f'''#define {csv._csv.shortName.val()}_START_SEC_VAR_{pim.swDataDefProps.swAddrMethod.ref().shortName.val()}
						#include "{csv._csv.shortName.val()}_MemMap.h"'''
					postdecl= f'''
					#define {csv._csv.shortName.val()}_STOP_SEC_VAR_{pim.swDataDefProps.swAddrMethod.ref().shortName.val()}
						#include "{csv._csv.shortName.val()}_MemMap.h"'''
				c << f'{_type.impl_name()} Rte_Pim_{instance._behavior.shortName.val()}_{pim.shortName.val()}{init};{postdecl}'

			# identify runnables to be scheduled
			for timingEvent in instance._behavior.event.TimingEvent:
				# all runnables triggered by a timing event should be scheduled
				runnable=instance._runnables[timingEvent.startOnEvent.ref()]
				mapping=runnable._taskMappings.select.findfirst(lambda e:e.RteEventRef.ref() == timingEvent)
				tasks[mapping.RteMappedToTaskRef.ref()].append((mapping,'TIMING-EVENT',runnable))
			for id,mode in instance._modes.items():
				# all modes shall have a function to set the mode and the mode clients may be scheduled to a runnable
				if mode._dataelementref.__len__() > 0:
					onExit=defaultdict(RteList)
					onTrans=defaultdict(RteList)
					onEntry=defaultdict(RteList)
					for modeswitchpoint in mode._dataelementref:
						for key,runnable in modeswitchpoint._runnables.items():
							if key=='modeAccessPoint':
								# this is a mode access point, ignore
								continue
							(point,modeObj) = key
							if point == 'ON-EXIT':
								onExit[modeObj.shortName.val()].extend(runnable)
							elif point == 'ON-ENTRY':
								onEntry[modeObj.shortName.val()].extend(runnable)
							elif point == 'ON-TRANS':
								onTrans[modeObj.shortName.val()].extend(runnable)
					def PrintSwitch(c, mode, runnableDict):
						for i,m in enumerate(mode._modeGroup.type.ref().modeDeclaration):
							runnables=runnableDict[m.shortName.val()].sort(key=lambda e: default(0xffffffff,e)._taskMappings[0].RtePositionInTask.val())
							if runnables.__len__() > 0:
								c << f'case {i}:'
								for runnable in runnables:
									c << runnable.print_call()
						c << '}'
					if onTrans.__len__() > 0:
						c << f'static void Rte_OnTrans_{instanceobj.shortName.val()}_{id[0].shortName.val()}_{id[1].shortName.val()}({mode._type.impl_name()} mode) {{'
						c << 'switch(mode) {'
						PrintSwitch(c,mode,onTrans)
					Rte_mode_current = f'{mode._type.impl_name()} Rte_mode_current_{instanceobj.shortName.val()}_{id[0].shortName.val()}_{id[1].shortName.val()}'
					Rte_mode_next = f'{mode._type.impl_name()} Rte_mode_next_{instanceobj.shortName.val()}_{id[0].shortName.val()}_{id[1].shortName.val()}'
					if mode._modeGroup.type.ref().initialMode:
						# should use sorted index if category is ALPHABETIC_ORDER and specified value if EXPLICIT_ORDER
						#if mode._modeGroup.type.ref().category.val() == 'ALPHABETIC_ORDER':
						initialMode=mode._modeGroup.type.ref().modeDeclaration.select.sorted(lambda e:e.shortName.val()).index(mode._modeGroup.type.ref().initialMode.ref())
					else:
						# unclear what value to use for initial mode if no initialMode configured, use transition value instead
						initialMode=len(mode._modeGroup.type.ref().modeDeclaration)
					ci << f'extern {Rte_mode_current};'
					c << f'{Rte_mode_current} = {initialMode};'
					ci << f'extern {Rte_mode_next};'
					c << f'{Rte_mode_next} = {initialMode};'
					c << f'static void Rte_mode_{instanceobj.shortName.val()}_{id[0].shortName.val()}_{id[1].shortName.val()}(void) {{'
					if onExit.__len__() > 0:
						c << f'switch(Rte_mode_current_{instanceobj.shortName.val()}_{id[0].shortName.val()}_{id[1].shortName.val()}({mode._type.impl_name()}) {{'
						PrintSwitch(c,mode,onExit)
					if onTrans.__len__() > 0:
						c << f'Rte_OnTrans_{instanceobj.shortName.val()}_{id[0].shortName.val()}_{id[1].shortName.val()}(Rte_mode_current_{instanceobj.shortName.val()}_{id[0].shortName.val()}_{id[1].shortName.val()});'
					c << f'Rte_mode_current_{instanceobj.shortName.val()}_{id[0].shortName.val()}_{id[1].shortName.val()} = Rte_mode_next_{instanceobj.shortName.val()}_{id[0].shortName.val()}_{id[1].shortName.val()};'
					if onTrans.__len__() > 0:
						c << f'Rte_OnTrans_{instanceobj.shortName.val()}_{id[0].shortName.val()}_{id[1].shortName.val()}(Rte_mode_current_{instanceobj.shortName.val()}_{id[0].shortName.val()}_{id[1].shortName.val()});'
					if onEntry.__len__() > 0:
						c << f'switch(Rte_mode_current_{instanceobj.shortName.val()}_{id[0].shortName.val()}_{id[1].shortName.val()}) {{'
						PrintSwitch(c,mode,onEntry)
					c << '}'
					Rte_Switch = f'Std_ReturnType Rte_Switch_{csv._csv.shortName.val()}_{id[0].shortName.val()}_{id[1].shortName.val()}({mode._type.impl_name()} mode)'
					ci << f'extern {Rte_Switch};'
					c << f'{Rte_Switch} {{'
					c << f'if(Rte_mode_next_{instanceobj.shortName.val()}_{id[0].shortName.val()}_{id[1].shortName.val()} != mode) {{\n'
					c << f'Rte_mode_next_{instanceobj.shortName.val()}_{id[0].shortName.val()}_{id[1].shortName.val()} = mode;'
					# use one task mapping, doesn't matter which since all modeswitches must be scheduled by the same task
					mappedRunnable=next(runnable for runnables in mode._dataelementref[0]._runnables.values() for runnable in runnables)
					taskMapping=mappedRunnable._taskMappings.select.findfirst(lambda e:e.RteEventRef.ref().startOnEvent.ref() == mappedRunnable._runnable,ModelNone)
					task = taskMapping.RteMappedToTaskRef.ref()
					if not task==None:
						if not taskMapping.RteUsedOsEventRef.ref()==None:
							c << f'SetEvent(TASK_ID_{task.shortName.val()},EVENT_MASK_{taskMapping.RteUsedOsEventRef.ref().shortName.val()});' 
						elif not taskMapping.RteUsedOsAlarmRef.ref()==None:
							c << f'ActivateTask(TASK_ID_{task.shortName.val()});'
						tasks[task].append((taskMapping,'MODE-SWITCH-EVENT',f'{instanceobj.shortName.val()}_{id[0].shortName.val()}_{id[1].shortName.val()}'))
					else:
						# no task reference
						c << f'Rte_mode_{instanceobj.shortName.val()}_{id[0].shortName.val()}_{id[1].shortName.val()}();'
					c << '}\nreturn RTE_E_OK;\n}'

	for task,events in tasks.items():
		if not task==None:
			events.sort(key=lambda e:default(0xFFFFFFFF,e)[0].RtePositionInTask.val())
			c << f'\nTASK({task.shortName.val()}) {{'
			if not events[0][0].RteUsedOsEventRef.ref()==None:
				osEvents=RteList(set(event[0].RteUsedOsEventRef.ref() for event in events))
				c << f'''while(1) {{
					EventMaskType event;
					WaitEvent(EVENT_MASK_{" | EVENT_MASK_".join(osEvents.shortName.val())});
					GetEvent(TASK_ID_{task.shortName.val()}, &event);
					ClearEvent(event & (EVENT_MASK_{" | EVENT_MASK_".join(osEvents.shortName.val())}));'''
				prevEvent = RteList()
				for (mapping,type,obj) in events:
					ev = mapping.RteUsedOsEventRef.ref()
					if prevEvent != ev:
						if prevEvent:
							c << '}'
						c << f'if(event & EVENT_MASK_{ev.shortName.val()}) {{'
						prevEvent=ev
					if type == 'TIMING-EVENT':
						c << obj.print_call()
					elif type == 'MODE-SWITCH-EVENT':
						c << f'Rte_mode_{obj}();'
				c << '}\n}'
			else:
				for (mapping,type,obj) in events:
					if type == 'TIMING-EVENT':
						c << obj.print_call()
					elif type == 'MODE-SWITCH-EVENT':
						c << f'if(Rte_mode_next_{obj} != Rte_mode_current_{obj}) {{'
						c << f'Rte_mode_{obj}();\n}}'
			c << '}'
	c.close()
	ci.close()

	c = CWriter('Rte_Param.c')
	c << '#include <Rte_Type.h>\n'
	for csv in csvs.values():
		for instanceobj,instance in csv._instances.items():
			for calparamobj,calparam in instance._calparams.items():
				if calparamobj.binding().name() == 'sharedParameter':
					name=f'Rte_CalPrm_Rom_{csv._csv.shortName.val()}_{calparamobj.shortName.val()}'
				else:
					name=f'Rte_CalPrm_Rom_{instanceobj.shortName.val()}_{calparamobj.shortName.val()}'					
				c << f'const {calparam._type.impl_name()} {name} = {calparam._type.VALUE2str(calparamobj.initValue[0])};'

	c.close()


	Rte_type_h.Write_Rte_type()

	c = CWriter('Rte.h')
	c << '''#ifndef RTE_H_
	#define RTE_H_

	#include "Std_Types.h"
	#include "Rte_Type.h"

	// error codes
	#define RTE_E_OK						0U
	#define RTE_E_NOK						1U
	#define RTE_E_INVALID					1U
	#define RTE_E_COM_STOPPED				128U
	#define RTE_E_TIMEOUT					129U
	#define RTE_E_LIMIT						130U
	#define RTE_E_NO_DATA					131U
	#define RTE_E_TRANSMIT_ACK				132U
	#define RTE_E_NEVER_RECEIVED			133U
	#define RTE_E_UNCONNECTED				134U
	#define RTE_E_IN_EXCLUSIVE_AREA			135U
	#define RTE_E_SEG_FAULT					136U
	#define RTE_E_OUT_OF_RANGE				137U
	#define RTE_E_SERIALIZATION_ERROR		138U
	#define RTE_E_HARD_TRANSFORMER_ERROR	138U
	#define RTE_E_SERIALIZATION_LIMIT		139U
	#define RTE_E_TRANSFORMER_LIMIT			139U
	#define RTE_E_SOFT_TRANSFORMER_ERROR	140U
	#define RTE_E_COM_BUSY					141U
	#define RTE_E_LOST_DATA                 64U
	#define RTE_E_MAX_AGE_EXCEEDED          64U

	#endif // RTE_H_
	'''

	c.close()

	c = CWriter('Rte_Main.h')
	c << '''#ifndef RTE_MAIN_H_
	#define RTE_MAIN_H_

	#include "Rte.h"

	Std_ReturnType Rte_Start(void);
	Std_ReturnType Rte_Stop(void);
	//void Rte_PartitionTerminated_<PID>(void)
	//void Rte_PartitionRestarting_<PID>(void)
	//Std_ReturnType Rte_RestartPartition_<PID>(void)
	//void Rte_Init_<InitContainer>(void)
	void Rte_StartTiming(void);

	#endif // RTE_MAIN_H_
	'''
	c.close()

	c = CWriter('Rte_Main.c')
	c << '''#include "Rte_Main.h"

	Std_ReturnType Rte_Start(void) {
		return E_OK;
	}
	Std_ReturnType Rte_Stop(void) {
		return E_OK;
	}
	//void Rte_PartitionTerminated_<PID>(void)
	//void Rte_PartitionRestarting_<PID>(void)
	//Std_ReturnType Rte_RestartPartition_<PID>(void)
	//void Rte_Init_<InitContainer>(void)
	void Rte_StartTiming(void) {
	}
	'''
	c.close()

def main(argv):
	import argparse
	_parser = argparse.ArgumentParser(description='Rte generator')
	_parser.add_argument('-o', '--outputDir', nargs='?', help='where to store the output files', default='./Rte')
	_parser.add_argument('-w', '--matlabWorkaround', action='store_true', help='Matlab have problems with Autosar types and a solution is to generate a _DEFINED_TYPEDEF_FOR_[typename]_', default=False)
	#_parser.add_argument('-c', '--config', nargs='?', help='Absolute path to the module configuration', default='')
	_args = _parser.parse_args(argv)
	global _outdir
	_outdir = _args.outputDir
	global _matlabTypeWorkaround
	_matlabTypeWorkaround = _args.matlabWorkaround
 
	GenRte()

	vprint('done')
